#include "../include/server.h"
int recvn(int sfd, void *p, int len)
{
    char *str = (char *)p;
    int cur = 0, left = len, ret;
    while (left > 0)
    {
        ret = recv(sfd, str + cur, left, 0);
        ERROR_CHECK(ret, -1, "recv");
        cur += ret;
        left -= ret;
    }
    return cur;
}
int sendn(int sfd, void *str, int len)
{
    char *mes = (char *)str;
    int left = len, cur = 0, ret;
    while (left > 0)
    {
        ret = send(sfd, mes + cur, left, 0);
        ERROR_CHECK(ret, -1, "send");
        left -= ret;
        cur += ret;
    }
    return cur;
}
int recv_file(int sfd, char *md5_str)
{
    Train train;
    printf("start recv_file\n");
    char file_path[MAXSTR] = "../user/";
    strcat(file_path, md5_str);
    int fd = open(file_path, O_CREAT | O_RDWR | O_APPEND, 0666);
    if (fd == -1)
    {
        printf("server open error\n");
        return F_ret;
    }
    memset(&train, 0, sizeof(train));
    int filesize;
    recvn(sfd, &train.len, sizeof(train.len));
    recvn(sfd, &filesize, train.len);
    printf("recv filesize=%d\n", filesize);
    if (filesize > BIGSIZE)
    {
        printf("recv big file\n");
        recv_big_file(fd, sfd, filesize);
    }
    else
    {
        printf("recv_reg_file\n");
        recv_reg_file(fd, sfd, filesize);
    }
    printf("recv file success\n");
    close(fd);
    return filesize;
}
void send_file(int sfd, char *md5, off_t exist_size)
{
    //先判断文件是否存在
    Train train;
    memset(&train, 0, sizeof(Train));

    char file_path[MAXSTR] = "../user/";
    strcat(file_path, md5);
    int fd = open(file_path, O_RDONLY);
    if (fd == -1)
    {
        printf("open error\n"); //本地不存在此文件
    }
    lseek(fd, exist_size, SEEK_SET);

    struct stat file_status;
    memset(&file_status, 0, sizeof(file_status));
    fstat(fd, &file_status);
    off_t file_size = file_status.st_size - exist_size;
    printf("file_size=%ld\n", file_size);
    memset(&train, 0, sizeof(train));

    //正常情况
    memcpy(train.buf, &file_size, sizeof(file_size));
    train.len = sizeof(file_size);
    sendn(sfd, &train, train.len + 4);

    if (file_size > BIGSIZE)
    {
        printf("send_big_file\n");
        send_big_file(fd, sfd, file_size, exist_size);
    }
    else
    {
        printf("send_reg_file file_size=%ld\n", file_size);
        send_reg_file(fd, sfd, file_size);
    }
    printf("send_file send file success\n");
    close(fd);
}
int judge_file_exit(Task *task, char *filename, int *exist, char *md5_str)
{
    //判断该用户该目录下是否存在此文件，若存在，则返回文件大小，不存在，则返回0
    char sql_cmd[MAXSTR] = {0};
    sprintf(sql_cmd, "select filename,filesize,md5 from TFILE where owner_id=%d and type=0 and parent_id=%d;", task->usr.usr_id, task->usr.dir_id);
    int ret = mysql_real_query(task->mysql_con, sql_cmd, strlen(sql_cmd));
    if (ret != 0)
    {
        printf("select error:%s\n", mysql_error(task->mysql_con));
    }
    MYSQL_RES *mysql_res;
    MYSQL_ROW mysql_row; //行数据
    mysql_res = mysql_store_result(task->mysql_con);
    while ((mysql_row = mysql_fetch_row(mysql_res)) != NULL)
    {
        if (strcmp(filename, mysql_row[0]) == 0)
        {
            *exist = 1;
            strcpy(md5_str, mysql_row[2]);
            return atoi(mysql_row[1]);
        }
    }
    return 0;
}
void send_big_file(int fd, int sfd, off_t file_size, off_t exist_size)
{
    char *p = (char *)mmap(NULL, file_size + exist_size, PROT_READ, MAP_SHARED, fd, 0);
    if (MAP_FAILED == p)
    {
        perror("mmap");
    }
    sendn(sfd, p + exist_size, file_size);
    munmap(p, file_size);
}
void send_reg_file(int fd, int sfd, off_t file_size)
{
    Train train;
    int ret, left = file_size, cur = 0;
    while (left > 0)
    {
        memset(&train, 0, sizeof(train));
        //正常情况
        ret = read(fd, train.buf, sizeof(train.buf));
        //测试断点续传
        // ret = read(fd, train.buf, left);
        if (ret == 0)
        {
            printf("read error\n");
            return;
        }

        train.len = ret;
        ret = sendn(sfd, &train, 4 + train.len);
        cur += train.len;
        left -= train.len;
    }
}
void recv_big_file(int fd, int sfd, off_t filesize)
{
    printf("recv_big_file=%ld\n", filesize);
    Train train;
    memset(&train, 0, sizeof(train));
    off_t left_size = filesize, cur = 0;
    int ret, recv_size;
    while (left_size > 0)
    {
        if (left_size > sizeof(train.buf))
        {
            recv_size = sizeof(train.buf);
        }
        else
        {
            recv_size = left_size;
        }
        ret = recvn(sfd, train.buf, recv_size);
        ret = write(fd, train.buf, ret);
        cur += ret;
        left_size -= ret;
    }
}
void recv_reg_file(int fd, int sfd, off_t filesize)
{
    printf("recv_reg_file\n");
    Train train;
    int left = filesize, cur = 0, ret = 0;
    while (left > 0)
    {
        printf("left=%d\n", left);
        memset(&train, 0, sizeof(train));
        recvn(sfd, &train.len, 4);
        recvn(sfd, train.buf, train.len);
        ret = write(fd, train.buf, train.len);
        if (ret == -1)
        {
            perror("write:");
            return;
        }
        cur += ret;
        left -= ret;
    }
}
